home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Mac Game Programming Gurus
/
TricksOfTheMacGameProgrammingGurus.iso
/
Book Chapters
/
03 - Advanced Graphics
/
Example 3
/
sprite.c
< prev
next >
Wrap
Text File
|
1995-02-27
|
9KB
|
310 lines
//
// File: sprite.c
//
// This file contains the routines to draw the sprites
//
// 2/19/95 -- Created by Mick
//
// include files
#include "global.h"
#include "sprite.h"
#include "main.h"
// defines for this file
#define kClearColor 0 // the clear color in this case is white
// global function declarations
tSpriteInfo *loadSprite( signed short inSpriteResID );
void disposeSprite( tSpriteInfo *inSpriteInfo );
void startSpriteDraw( Rect *inClipRect, PixMapHandle inDestPixMap );
void endSpriteDraw( void );
void drawSprite( tSpriteInfo *inSpriteInfo, Point inWhere );
// global data owned by this file
// local function declarations
static void renderSpriteClipped( tSpriteInfo *inSpriteInfo, Rect *inDestRect );
static void renderSpriteUnclipped( tSpriteInfo *inSpriteInfo, Rect *inDestRect );
// static data
Rect sClipRect; // the rectangle to clip to
PixMapHandle sDestPixMap; // where we are going to draw this data
unsigned long sRowBytes; // the row bytes of the pixmap
unsigned char *sBaseAddr; // the base address of the pixmap
// functions
//
// loadSprite -
//
// Loads/allocates all the data for a sprite.
//
tSpriteInfo *loadSprite( signed short inSpriteResID )
{
tSpriteInfo *newSprite; // the new sprite data
PicHandle spritePict; // the sprite/mask picture
CGrafPtr oldCPort; // the graf port that is in place when we are called
GDHandle oldDevice; // the gdevice that is in place when we are called
// create the sprite info record
newSprite = ( tSpriteInfo * )NewPtr( sizeof( tSpriteInfo ) );
// load the pict
spritePict = GetPicture( inSpriteResID );
if ( spritePict == ( PicHandle )kNil )
{
// if it did not load, drop into the debugger -- real programs would have error checking
Debugger();
}
// copy its bounds rect
newSprite->fSpriteRect = ( *spritePict )->picFrame;
// create a gworld for it
NewGWorld( &newSprite->fSpriteWorld, 8, &( newSprite->fSpriteRect ),
gAppColorTable, ( GDHandle )kNil, keepLocal );
// extract the pixmap handle
newSprite->fSpritePix = GetGWorldPixMap( newSprite->fSpriteWorld );
// save the current port and gdevice
GetGWorld( &oldCPort, &oldDevice );
// set the offscreen buffer as current ( and lock the pixel map )
SetGWorld( newSprite->fSpriteWorld, ( GDHandle )kNil );
LockPixels( newSprite->fSpritePix );
// draw the picture
EraseRect( &( newSprite->fSpriteRect ) );
DrawPicture( spritePict, &( newSprite->fSpriteRect ) );
// restore the current port and gdevice
UnlockPixels( newSprite->fSpritePix );
SetGWorld( oldCPort, oldDevice );
// dump the pict
ReleaseResource( ( Handle )spritePict );
// return the new sprite!
return newSprite;
}
//
// disposeSprite -
//
// Disposes/releases all the memory used in a sprite
//
void disposeSprite( tSpriteInfo *inSpriteInfo )
{
// dump the gworld
DisposeGWorld( inSpriteInfo->fSpriteWorld );
// free the structure
DisposePtr( ( Ptr )inSpriteInfo );
}
//
// startSpriteDraw -
//
// Prepare the sprite draw. Assumes that the port is set to the destination port.
//
void startSpriteDraw( Rect *inClipRect, PixMapHandle inDestPixMap )
{
// set the clip region to be the passed in rect
sClipRect = *inClipRect;
// save the pix map info (so we can use it)
sDestPixMap = inDestPixMap;
// extract the needed information from the pixmap
sBaseAddr = ( unsigned char * )GetPixBaseAddr( sDestPixMap );
sRowBytes = ( *sDestPixMap )->rowBytes & 0x3FFF;
}
//
// endSpriteDraw -
//
// End the sprite draw sequence.
//
void endSpriteDraw( void )
{
}
//
// drawSprite -
//
// Draw the sprite in the port.
//
void drawSprite( tSpriteInfo *inSpriteInfo, Point inWhere )
{
Rect destRect; // where we want to draw the sprite
// calculate the destination rect
destRect = inSpriteInfo->fSpriteRect;
OffsetRect( &destRect, inWhere.h, inWhere.v );
// determine if the spite needs to be drawn at all
if( destRect.top >= sClipRect.bottom || destRect.bottom <= sClipRect.top ||
destRect.left >= sClipRect.right || destRect.right <= sClipRect.left )
{
// no need to draw, goodbye
return;
}
// determine if the sprite will be clipped
if ( destRect.top < sClipRect.top || destRect.bottom > sClipRect.bottom ||
destRect.left < sClipRect.left || destRect.right > sClipRect.right )
{
// handle the clipped case
renderSpriteClipped( inSpriteInfo, &destRect );
}
else
{
// handle the unclipped case
renderSpriteUnclipped( inSpriteInfo, &destRect );
}
}
//
// renderSpriteClipped -
//
// Draw the spite, deal with clipping.
//
void renderSpriteClipped( tSpriteInfo *inSpriteInfo, Rect *inDestRect )
{
Rect srcRect; // the rect that defines the clipped shape (source coordinates)
Rect destRect; // the rect that defines the clipped shape (destination coodinates)
unsigned char *srcPtr; // our current position in the shape
unsigned char *destPtr; // our current position in the destination
unsigned long srcRowBytes; // the row bytes of the source data
unsigned char *srcBaseAddr; // the base address of the source data
unsigned char *srcRowStart; // the start of the current row in the source
unsigned char *destRowStart; // the start of the current row in the destination
unsigned long xCounter; // a counter to scan the row
unsigned long yCounter; // a counter to scan the column
// create a clipped rect in the coordinates of the sprite
srcRect.left = inDestRect->left < sClipRect.left ? sClipRect.left - inDestRect->left : 0;
srcRect.right = inDestRect->right > sClipRect.right ? sClipRect.right - inDestRect->left : inDestRect->right - inDestRect->left;
srcRect.top = inDestRect->top < sClipRect.top ? sClipRect.top - inDestRect->top : 0;
srcRect.bottom = inDestRect->bottom > sClipRect.bottom ? sClipRect.bottom - inDestRect->top : inDestRect->bottom - inDestRect->top;
// create the same rect in the coordinates of the destination
destRect.left = inDestRect->left + srcRect.left;
destRect.right = inDestRect->left + srcRect.right;
destRect.top = inDestRect->top + srcRect.top;
destRect.bottom = inDestRect->top + srcRect.bottom;
// lock down the pixmap for the sprite
LockPixels( inSpriteInfo->fSpritePix );
// extract the needed information from the pixmap
srcBaseAddr = ( unsigned char * )GetPixBaseAddr( inSpriteInfo->fSpritePix );
srcRowBytes = ( *( inSpriteInfo->fSpritePix ) )->rowBytes & 0x3FFF;
// determine the starting pointers
srcRowStart = srcBaseAddr + srcRect.top * srcRowBytes + srcRect.left;
destRowStart = sBaseAddr + destRect.top * sRowBytes + destRect.left;
// loop through the data
for( yCounter = srcRect.bottom - srcRect.top; yCounter > 0; yCounter-- )
{
// set the scanning pointers
srcPtr = srcRowStart;
destPtr = destRowStart;
// draw this row
for( xCounter = srcRect.right - srcRect.left; xCounter > 0; xCounter-- )
{
if ( *srcPtr != kClearColor )
{
*destPtr = *srcPtr;
}
destPtr++;
srcPtr++;
}
// move to the next row
srcRowStart += srcRowBytes;
destRowStart += sRowBytes;
}
// unlock the pixels
UnlockPixels( inSpriteInfo->fSpritePix );
}
//
// renderSpriteUnclipped -
//
// Draw the sprite, no clipping needed
//
void renderSpriteUnclipped( tSpriteInfo *inSpriteInfo, Rect *inDestRect )
{
unsigned char *srcPtr; // our current position in the shape
unsigned char *destPtr; // our current position in the destination
unsigned long srcRowBytes; // the row bytes of the source data
unsigned char *srcBaseAddr; // the base address of the source data
unsigned char *srcRowStart; // the start of the current row in the source
unsigned char *destRowStart; // the start of the current row in the destination
unsigned long xCounter; // a counter to scan the row
unsigned long yCounter; // a counter to scan the column
// lock down the pixmap for the sprite
LockPixels( inSpriteInfo->fSpritePix );
// extract the needed information from the pixmap
srcBaseAddr = ( unsigned char * )GetPixBaseAddr( inSpriteInfo->fSpritePix );
srcRowBytes = ( *( inSpriteInfo->fSpritePix ) )->rowBytes & 0x3FFF;
// determine the starting pointers
srcRowStart = srcBaseAddr;
destRowStart = sBaseAddr + inDestRect->top * sRowBytes + inDestRect->left;
// loop through the data
for( yCounter = inSpriteInfo->fSpriteRect.bottom; yCounter > 0; yCounter-- )
{
// set the scanning pointers
srcPtr = srcRowStart;
destPtr = destRowStart;
// draw this row
for( xCounter = inSpriteInfo->fSpriteRect.right; xCounter > 0; xCounter-- )
{
if ( *srcPtr != kClearColor )
{
*destPtr = *srcPtr;
}
destPtr++;
srcPtr++;
}
// move to the next row
srcRowStart += srcRowBytes;
destRowStart += sRowBytes;
}
// unlock the pixels
UnlockPixels( inSpriteInfo->fSpritePix );
}